home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / X11R4 / cmds / X / dix / resource.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-14  |  13.3 KB  |  526 lines

  1. /************************************************************
  2. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  3. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Digital or MIT not be
  12. used in advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.  
  14.  
  15. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22.  
  23. ********************************************************/
  24.  
  25. /* $XConsortium: resource.c,v 1.79 89/10/08 15:16:32 rws Exp $ */
  26.  
  27. /*    Routines to manage various kinds of resources:
  28.  *
  29.  *    CreateNewResourceType, CreateNewResourceClass, InitClientResources,
  30.  *    FakeClientID, AddResource, FreeResource, FreeClientResources,
  31.  *    FreeAllResources, LookupIDByType, LookupIDByClass
  32.  */
  33.  
  34. /* 
  35.  *      a resource is a 32 bit quantity.  the upper 12 bits are client id.  
  36.  *      client provides a 19 bit resource id. this is "hashed" by me by
  37.  *      taking the 10 lower bits and xor'ing with the mid 10 bits.
  38.  *
  39.  *      It is sometimes necessary for the server to create an ID that looks
  40.  *      like it belongs to a client.  This ID, however,  must not be one
  41.  *      the client actually can create, or we have the potential for conflict.
  42.  *      The 20th bit of the ID is resevered for the server's use for this
  43.  *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
  44.  *      1, and an otherwise unused ID in the low 19 bits, we can create a
  45.  *      resource "owned" by the client.
  46.  *      
  47.  *      The following IDs are currently reserved for siccing on the client:
  48.  *      1 - allocated color to be freed when the client dies
  49.  */
  50.  
  51. #include "X.h"
  52. #include "misc.h"
  53. #include "os.h"
  54. #include "resource.h"
  55. #include "dixstruct.h" 
  56. #include "opaque.h"
  57.  
  58. extern void HandleSaveSet();
  59. extern void FlushClientCaches();
  60. static void RebuildTable();
  61.  
  62. #define INITBUCKETS 64
  63. #define INITHASHSIZE 6
  64. #define MAXHASHSIZE 11
  65.  
  66. typedef struct _Resource {
  67.     struct _Resource    *next;
  68.     XID            id;
  69.     RESTYPE        type;
  70.     pointer        value;
  71. } ResourceRec, *ResourcePtr;
  72. #define NullResource ((ResourcePtr)NULL)
  73.  
  74. typedef struct _ClientResource {
  75.     ResourcePtr *resources;
  76.     int        elements;
  77.     int        buckets;
  78.     int        hashsize;    /* log(2)(buckets) */
  79.     XID        fakeID;
  80.     XID        expectID;
  81. } ClientResourceRec;
  82.  
  83. static RESTYPE lastResourceType;
  84. static RESTYPE lastResourceClass;
  85. static RESTYPE TypeMask;
  86.  
  87. typedef int (*DeleteType)();
  88.  
  89. static DeleteType *DeleteFuncs = (DeleteType *)NULL;
  90.  
  91. RESTYPE
  92. CreateNewResourceType(deleteFunc)
  93.     DeleteType deleteFunc;
  94. {
  95.     RESTYPE next = lastResourceType + 1;
  96.     DeleteType *funcs;
  97.  
  98.     if (next & lastResourceClass)
  99.     return 0;
  100.     funcs = (DeleteType *)xrealloc(DeleteFuncs,
  101.                    (next + 1) * sizeof(DeleteType));
  102.     if (!funcs)
  103.     return 0;
  104.     lastResourceType = next;
  105.     DeleteFuncs = funcs;
  106.     DeleteFuncs[next] = deleteFunc;
  107.     return next;
  108. }
  109.  
  110. RESTYPE
  111. CreateNewResourceClass()
  112. {
  113.     RESTYPE next = lastResourceClass >> 1;
  114.  
  115.     if (next & lastResourceType)
  116.     return 0;
  117.     lastResourceClass = next;
  118.     TypeMask = next - 1;
  119.     return next;
  120. }
  121.  
  122. ClientResourceRec clientTable[MAXCLIENTS];
  123.  
  124. /*****************
  125.  * InitClientResources
  126.  *    When a new client is created, call this to allocate space
  127.  *    in resource table
  128.  *****************/
  129.  
  130. Bool
  131. InitClientResources(client)
  132.     ClientPtr client;
  133. {
  134.     register int i, j;
  135.  
  136.     if (client == serverClient)
  137.     {
  138.     extern int DeleteWindow(), dixDestroyPixmap(), FreeGC();
  139.     extern int CloseFont(), FreeCursor();
  140.     extern int FreeColormap(), FreeClientPixels();
  141.     extern int OtherClientGone(), DeletePassiveGrab();
  142.  
  143.     lastResourceType = RT_LASTPREDEF;
  144.     lastResourceClass = RC_LASTPREDEF;
  145.     TypeMask = RC_LASTPREDEF - 1;
  146.     if (DeleteFuncs)
  147.         xfree(DeleteFuncs);
  148.     DeleteFuncs = (DeleteType *)xalloc((lastResourceType + 1) *
  149.                        sizeof(DeleteType));
  150.     if (!DeleteFuncs)
  151.         return FALSE;
  152.     DeleteFuncs[RT_WINDOW & TypeMask] = DeleteWindow;
  153.     DeleteFuncs[RT_PIXMAP & TypeMask] = dixDestroyPixmap;
  154.     DeleteFuncs[RT_GC & TypeMask] = FreeGC;
  155.     DeleteFuncs[RT_FONT & TypeMask] = CloseFont;
  156.     DeleteFuncs[RT_CURSOR & TypeMask] = FreeCursor;
  157.     DeleteFuncs[RT_COLORMAP & TypeMask] = FreeColormap;
  158.     DeleteFuncs[RT_CMAPENTRY & TypeMask] = FreeClientPixels;
  159.     DeleteFuncs[RT_OTHERCLIENT & TypeMask] = OtherClientGone;
  160.     DeleteFuncs[RT_PASSIVEGRAB & TypeMask] = DeletePassiveGrab;
  161.     }
  162.     clientTable[i = client->index].resources =
  163.     (ResourcePtr *)xalloc(INITBUCKETS*sizeof(ResourcePtr));
  164.     if (!clientTable[i].resources)
  165.     return FALSE;
  166.     clientTable[i].buckets = INITBUCKETS;
  167.     clientTable[i].elements = 0;
  168.     clientTable[i].hashsize = INITHASHSIZE;
  169.     clientTable[i].fakeID = 100;
  170.     clientTable[i].expectID = client->clientAsMask;
  171.     for (j=0; j<INITBUCKETS; j++) 
  172.     {
  173.         clientTable[i].resources[j] = NullResource;
  174.     }
  175.     return TRUE;
  176. }
  177.  
  178. static int
  179. Hash(client, id)
  180.     int client;
  181.     register XID id;
  182. {
  183.     id &= RESOURCE_ID_MASK;
  184.     switch (clientTable[client].hashsize)
  185.     {
  186.     case 6:
  187.         return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
  188.     case 7:
  189.         return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
  190.     case 8:
  191.         return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
  192.     case 9:
  193.         return ((int)(0x1FF & (id ^ (id>>9))));
  194.     case 10:
  195.         return ((int)(0x3FF & (id ^ (id>>10))));
  196.     case 11:
  197.         return ((int)(0x7FF & (id ^ (id>>11))));
  198.     }
  199.     return -1;
  200. }
  201.  
  202. XID
  203. FakeClientID(client)
  204.     int client;
  205. {
  206.     return (
  207.         (client<<CLIENTOFFSET) + (SERVER_BIT) +
  208.         ((clientTable[client].fakeID++) & RESOURCE_ID_MASK));
  209. }
  210.  
  211. Bool
  212. AddResource(id, type, value)
  213.     XID id;
  214.     RESTYPE type;
  215.     pointer value;
  216. {
  217.     int client;
  218.     register ClientResourceRec *rrec;
  219.     register ResourcePtr res, *head;
  220.         
  221.     client = CLIENT_ID(id);
  222.     rrec = &clientTable[client];
  223.     if (!rrec->buckets)
  224.     {
  225.     ErrorF("AddResource(%x, %x, %x), client=%d \n",
  226.         id, type, value, client);
  227.         FatalError("client not in use\n");
  228.     }
  229.     if ((rrec->elements >= 4*rrec->buckets) &&
  230.     (rrec->hashsize < MAXHASHSIZE))
  231.     RebuildTable(client);
  232.     head = &rrec->resources[Hash(client, id)];
  233.     res = (ResourcePtr)xalloc(sizeof(ResourceRec));
  234.     if (!res)
  235.     {
  236.     (*DeleteFuncs[type & TypeMask])(value, id);
  237.     return FALSE;
  238.     }
  239.     res->next = *head;
  240.     res->id = id;
  241.     res->type = type;
  242.     res->value = value;
  243.     *head = res;
  244.     rrec->elements++;
  245.     if (!(id & SERVER_BIT) && (id >= rrec->expectID))
  246.     rrec->expectID = id + 1;
  247.     return TRUE;
  248. }
  249.  
  250. static void
  251. RebuildTable(client)
  252.     int client;
  253. {
  254.     register int j;
  255.     register ResourcePtr res, next;
  256.     ResourcePtr **tails, *resources;
  257.     register ResourcePtr **tptr, *rptr;
  258.  
  259.     /*
  260.      * For now, preserve insertion order, since some ddx layers depend
  261.      * on resources being free in the opposite order they are added.
  262.      */
  263.  
  264.     j = 2 * clientTable[client].buckets;
  265.     tails = (ResourcePtr **)ALLOCATE_LOCAL(j * sizeof(ResourcePtr *));
  266.     if (!tails)
  267.     return;
  268.     resources = (ResourcePtr *)xalloc(j * sizeof(ResourcePtr));
  269.     if (!resources)
  270.     {
  271.     DEALLOCATE_LOCAL(tails);
  272.     return;
  273.     }
  274.     for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
  275.     {
  276.     *rptr = NullResource;
  277.     *tptr = rptr;
  278.     }
  279.     clientTable[client].hashsize++;
  280.     for (j = clientTable[client].buckets,
  281.      rptr = clientTable[client].resources;
  282.      --j >= 0;
  283.      rptr++)
  284.     {
  285.     for (res = *rptr; res; res = next)
  286.     {
  287.         next = res->next;
  288.         res->next = NullResource;
  289.         tptr = &tails[Hash(client, res->id)];
  290.         **tptr = res;
  291.         *tptr = &res->next;
  292.     }
  293.     }
  294.     DEALLOCATE_LOCAL(tails);
  295.     clientTable[client].buckets *= 2;
  296.     xfree(clientTable[client].resources);
  297.     clientTable[client].resources = resources;
  298. }
  299.  
  300. void
  301. FreeResource(id, skipDeleteFuncType)
  302.     XID id;
  303.     RESTYPE skipDeleteFuncType;
  304. {
  305.     int        cid;
  306.     register    ResourcePtr res;
  307.     register    ResourcePtr *prev, *head;
  308.     register    int *eltptr;
  309.     int        elements;
  310.     Bool    gotOne = FALSE;
  311.  
  312.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  313.     {
  314.     head = &clientTable[cid].resources[Hash(cid, id)];
  315.     eltptr = &clientTable[cid].elements;
  316.  
  317.     prev = head;
  318.     while (res = *prev)
  319.     {
  320.         if (res->id == id)
  321.         {
  322.         RESTYPE rtype = res->type;
  323.         *prev = res->next;
  324.         elements = --*eltptr;
  325.         if (rtype & RC_CACHED)
  326.             FlushClientCaches(res->id);
  327.         if (rtype != skipDeleteFuncType)
  328.             (*DeleteFuncs[rtype & TypeMask])(res->value, res->id);
  329.         xfree(res);
  330.         if (*eltptr != elements)
  331.             prev = head; /* prev may no longer be valid */
  332.         gotOne = TRUE;
  333.         }
  334.         else
  335.         prev = &res->next;
  336.         }
  337.     if(clients[cid] && (id == clients[cid]->lastDrawableID))
  338.     {
  339.         clients[cid]->lastDrawable = (DrawablePtr) NULL;
  340.         clients[cid]->lastDrawableID = INVALID;
  341.     }
  342.     }
  343.     if (!gotOne)
  344.     FatalError("Freeing resource id=%X which isn't there", id);
  345. }
  346. void
  347. FreeResourceByType(id, type, skipFree)
  348.     XID id;
  349.     RESTYPE type;
  350.     Bool    skipFree;
  351. {
  352.     int        cid;
  353.     register    ResourcePtr res;
  354.     register    ResourcePtr *prev, *head;
  355.  
  356.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  357.     {
  358.     head = &clientTable[cid].resources[Hash(cid, id)];
  359.  
  360.     prev = head;
  361.     while (res = *prev)
  362.     {
  363.         if (res->id == id && res->type == type)
  364.         {
  365.         *prev = res->next;
  366.         if (type & RC_CACHED)
  367.             FlushClientCaches(res->id);
  368.         if (!skipFree)
  369.             (*DeleteFuncs[type & TypeMask])(res->value, res->id);
  370.         xfree(res);
  371.         break;
  372.         }
  373.         else
  374.         prev = &res->next;
  375.         }
  376.     if(clients[cid] && (id == clients[cid]->lastDrawableID))
  377.     {
  378.         clients[cid]->lastDrawable = (DrawablePtr) NULL;
  379.         clients[cid]->lastDrawableID = INVALID;
  380.     }
  381.     }
  382. }
  383.  
  384. /*
  385.  * Change the value associated with a resource id.  Caller
  386.  * is responsible for "doing the right thing" with the old
  387.  * data
  388.  */
  389.  
  390. Bool
  391. ChangeResourceValue (id, rtype, value)
  392.     XID    id;
  393.     RESTYPE rtype;
  394.     pointer value;
  395. {
  396.     int    cid;
  397.     register    ResourcePtr res;
  398.  
  399.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  400.     {
  401.     res = clientTable[cid].resources[Hash(cid, id)];
  402.  
  403.     for (; res; res = res->next)
  404.         if ((res->id == id) && (res->type == rtype))
  405.         {
  406.         if (rtype & RC_CACHED)
  407.             FlushClientCaches(res->id);
  408.         res->value = value;
  409.         return TRUE;
  410.         }
  411.     }
  412.     return FALSE;
  413. }
  414.  
  415. void
  416. FreeClientResources(client)
  417.     ClientPtr client;
  418. {
  419.     register ResourcePtr *resources;
  420.     register ResourcePtr this;
  421.     int j;
  422.  
  423.     /* This routine shouldn't be called with a null client, but just in
  424.     case ... */
  425.  
  426.     if (!client)
  427.     return;
  428.  
  429.     HandleSaveSet(client);
  430.  
  431.     resources = clientTable[client->index].resources;
  432.     for (j=0; j < clientTable[client->index].buckets; j++) 
  433.     {
  434.         /* It may seem silly to update the head of this resource list as
  435.     we delete the members, since the entire list will be deleted any way, 
  436.     but there are some resource deletion functions "FreeClientPixels" for 
  437.     one which do a LookupID on another resource id (a Colormap id in this
  438.     case), so the resource list must be kept valid up to the point that
  439.     it is deleted, so every time we delete a resource, we must update the
  440.     head, just like in FreeResource. I hope that this doesn't slow down
  441.     mass deletion appreciably. PRH */
  442.  
  443.     ResourcePtr *head;
  444.  
  445.     head = &resources[j];
  446.  
  447.         for (this = *head; this; this = *head)
  448.     {
  449.         RESTYPE rtype = this->type;
  450.         *head = this->next;
  451.         if (rtype & RC_CACHED)
  452.         FlushClientCaches(this->id);
  453.         (*DeleteFuncs[rtype & TypeMask])(this->value, this->id);
  454.         xfree(this);        
  455.     }
  456.     }
  457.     xfree(clientTable[client->index].resources);
  458.     clientTable[client->index].buckets = 0;
  459. }
  460.  
  461. FreeAllResources()
  462. {
  463.     int    i;
  464.  
  465.     for (i=0; i<currentMaxClients; i++) 
  466.     {
  467.         if (clientTable[i].buckets) 
  468.         FreeClientResources(clients[i]);
  469.     }
  470. }
  471.  
  472. Bool
  473. LegalNewID(id, client)
  474.     XID id;
  475.     register ClientPtr client;
  476. {
  477.     return ((client->clientAsMask == CLIENT_BITS(id)) && !(id & SERVER_BIT) &&
  478.         ((clientTable[client->index].expectID <= id) ||
  479.          !LookupIDByClass(id, RC_ANY)));
  480. }
  481.  
  482. /*
  483.  *  LookupIDByType returns the object with the given id and type, else NULL.
  484.  */ 
  485. pointer
  486. LookupIDByType(id, rtype)
  487.     XID id;
  488.     RESTYPE rtype;
  489. {
  490.     int    cid;
  491.     register    ResourcePtr res;
  492.  
  493.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  494.     {
  495.     res = clientTable[cid].resources[Hash(cid, id)];
  496.  
  497.     for (; res; res = res->next)
  498.         if ((res->id == id) && (res->type == rtype))
  499.         return res->value;
  500.     }
  501.     return (pointer)NULL;
  502. }
  503.  
  504. /*
  505.  *  LookupIDByClass returns the object with the given id and any one of the
  506.  *  given classes, else NULL.
  507.  */ 
  508. pointer
  509. LookupIDByClass(id, classes)
  510.     XID id;
  511.     RESTYPE classes;
  512. {
  513.     int    cid;
  514.     register    ResourcePtr res;
  515.  
  516.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  517.     {
  518.     res = clientTable[cid].resources[Hash(cid, id)];
  519.  
  520.     for (; res; res = res->next)
  521.         if ((res->id == id) && (res->type & classes))
  522.         return res->value;
  523.     }
  524.     return (pointer)NULL;
  525. }
  526.